package com.yonder.test.waitnotify;

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;

public class Box1 implements IBox {
	
	private static final int getTime = 201;
	private static final int addTime = 200;
	
	private Object getLock = new Object();
	private Object putLock = new Object();

	private Queue<String> productions = new ConcurrentLinkedQueue<String>();
	private int maxSize;

    /** Current number of elements */
    private final AtomicInteger count = new AtomicInteger();
	
	public Box1(int maxSize) {
		super();
		this.maxSize = maxSize;
	}

    /**
     * Signals a waiting take. Called only from put/offer (which do not
     * otherwise ordinarily lock takeLock.)
     */
    private void signalNotEmpty() {
    	System.out.println("signalNotEmpty");
		synchronized (getLock) {
			getLock.notify();
		}
    }
    /**
     * Signals a waiting put. Called only from take/poll.
     */
    private void signalNotFull() {
    	System.out.println("signalNotFull");
		synchronized (putLock) {
			putLock.notify();
		}
    }
	
	public String get(int id) {
		int c = 0;
		String production;
		synchronized (getLock) {
			try {
				while (productions.size() <= 0) {
					getLock.wait();
				}
				Thread.sleep(getTime);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			production = productions.poll();
	        c = count.getAndDecrement();
			if (c > 1) {
				getLock.notify();
			}
		}
		if (c == maxSize) {
			signalNotFull();
		}
		return production;
	}
	
	public String add(String production, int id) {
        int c = -1;
		synchronized (putLock) {
			try {
				while (productions.size() >= maxSize) {
					putLock.wait();
				}
				Thread.sleep(addTime);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			productions.add(production);
			c = count.getAndIncrement();
			if (c + 1 < maxSize) {
				putLock.notify();
			}
		}
		if (c == 0) {
			signalNotEmpty();
		}
		return production;
	}
	
	
	public int getProductionCount() {
		return productions.size();
	}
	public int getMaxSize() {
		return maxSize;
	}
	public void setMaxSize(int maxSize) {
		this.maxSize = maxSize;
	}
}
